/**
*@file       pnsessionaction.cpp
*@brief      performer impl
*
*@author     graywind
*@version    1.0.0.0
*@data       2012/03/17
*/
#include "../include/pnsessionaction.h"
#include "boost/bind.hpp"

using namespace pnNetlib;

/***************************************************************************************************************************/
pnSessionAction::pnSessionAction():
m_bAccept(false),
m_pAcceptor(0),
m_listenThread(0)
{

}

/***************************************************************************************************************************/
pnSessionAction::~pnSessionAction()
{
	if(is_init() == true)
	{
		close_all_session();
        if(m_pAcceptor != 0)
            delete m_pAcceptor;	
	}
}

/***************************************************************************************************************************/
bool
pnSessionAction::init(boost::asio::io_service &ioService, int max_session, long buffer_length)
{
	if(is_init() == false)
	{
		if(prepare(ioService, max_session, buffer_length) == true)
		{
			m_pAcceptor = new boost::asio::ip::tcp::acceptor(ioService);
			return true;
		}
	}

	return false;
}

/***************************************************************************************************************************/
void
pnSessionAction::accept(pnSession::SessionPtr session, MsgProc msgProc)
{
	if(session != 0)
	{
		session->set_msg_proc(msgProc);
        session->set_close_proc(boost::bind(&pnSessionAction::recycle, this, session->get_id(), Usage_Listen));

		boost::system::error_code ec;
		m_pAcceptor->accept(session->get_socket(), ec);

        inc_usage_count(Usage_Listen);

		if(!ec)
			session->start(Usage_Listen);
		else
			recycle(session->get_id(), Usage_Listen);

        if(msgProc != 0)
			msgProc(session->get_id(), 0, 0, 0, Listen, ec.value());
	}
}

/***************************************************************************************************************************/
void
pnSessionAction::accept_work(MsgProc msgProc)
{
	while(m_bAccept)
	{
		pnSession::SessionPtr validSession = get_valid_session();
	    if(validSession != 0)
			accept(validSession, msgProc);
	}
}

/***************************************************************************************************************************/
bool
pnSessionAction::start_listen(unsigned short port, MsgProc msgProc)
{
	if(is_init() == true)
	{
		if(m_bAccept == false)
		{
			boost::asio::ip::tcp::endpoint ep(boost::asio::ip::tcp::v4(), port);
			m_pAcceptor->open(ep.protocol());
			boost::asio::socket_base::reuse_address option(false);
			m_pAcceptor->set_option(option);
			boost::asio::socket_base::non_blocking_io  non_block(false);
			m_pAcceptor->io_control(non_block);
			m_pAcceptor->bind(ep);
			m_pAcceptor->listen(m_iMaxSession);

            m_listenThread = new boost::thread(boost::bind(&pnSessionAction::accept_work, this, msgProc));
            inter_lock::exchange((long int*)&m_bAccept, 1);
			return true;
		}
	}

	return false;
}

/***************************************************************************************************************************/
int
pnSessionAction::start_new_connection(const std::string &ip, unsigned short port, MsgProc msgProc)
{
	if(is_init() == true)
	{
		pnSession::SessionPtr session = get_valid_session();
		if(session != 0)
		{
			int session_id = session->get_id();
			session->set_close_proc(boost::bind(&pnSessionAction::recycle, this, session_id, Usage_Connect));
			session->set_msg_proc(msgProc);
            inc_usage_count(Usage_Connect);
			session->connect(ip, port);
			return session_id;
		}
	}

	return -1;
}

/***************************************************************************************************************************/
void 
pnSessionAction::close_session(int session_index)
{
	vanish(session_index);
}

/***************************************************************************************************************************/
void
pnSessionAction::close_all_session()
{
    vanish();
}

/***************************************************************************************************************************/
void
pnSessionAction::close_listen()
{
	if(m_bIsInit == true)
	{
		m_pAcceptor->close();

		inter_lock::exchange((long int*)&m_bAccept, 0);
		if(m_listenThread != 0)
		{
			delete m_listenThread;
			m_listenThread = 0;
		}
	}
}
